package net.sparrow.gui.drawing;

import java.nio.ByteBuffer;
import java.nio.DoubleBuffer;
import java.nio.FloatBuffer;
import java.util.ArrayList;

import net.minecraft.src.AxisAlignedBB;
import net.minecraft.src.Entity;
import net.minecraft.src.EntityClientPlayerMP;
import net.minecraft.src.EntityLivingBase;
import net.minecraft.src.Minecraft;
import net.minecraft.src.RenderManager;
import net.sparrow.Sparrow;
import net.sparrow.util.SpLocation;
import net.sparrow.util.Util;

import org.lwjgl.BufferUtils;
import org.lwjgl.opengl.GL11;
import org.lwjgl.opengl.GL12;
import org.lwjgl.opengl.GL30;

public class DrawManager {


	/**Saves all current settings
	 * in the openGL rendering context (RC).
	 * make sure to restoreDrawContext().
	 * Note: the openGL settings will not be cleared as this happens!
	 */
	public void saveDrawContext() {
		GL11.glPushMatrix();
		GL11.glPushAttrib(GL11.GL_ALL_ATTRIB_BITS);
		GL11.glPushClientAttrib(GL11.GL_ALL_ATTRIB_BITS);
	}

	/**Restores the last saved RC.
	 * 
	 */
	public void restoreDrawContext() {
		GL11.glPopClientAttrib();
		GL11.glPopAttrib();
		GL11.glPopMatrix();
	}

	public void drawGradientRect(SpScreenCoord coord, SpScreenCoord coord2, SpColor color1, SpColor color2) {
		SpScreenCoord actual = coord.asActualCoords();
		SpScreenCoord actual2 = coord2.asActualCoords();
		GL11.glPushMatrix();
		this.disableDefaults();
		//this.setupOverlayRendering();
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glDisable(GL11.GL_LIGHTING); //2896. Lighting does not apply to this "layer"
		GL11.glEnable(GL11.GL_ALPHA_TEST);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // transparent color enabled basically
		GL11.glDisable(GL11.GL_TEXTURE_2D); //3553. Not drawing textures, just colors
		GL11.glShadeModel(GL11.GL_SMOOTH);
		GL11.glBegin(GL11.GL_QUADS);
		color1.setOGLColor();
		GL11.glVertex2d(actual.getX(), actual.getY());
		GL11.glVertex2d(actual.getX(), actual2.getY());
		color2.setOGLColor();
		GL11.glVertex2d(actual2.getX(), actual2.getY());
		GL11.glVertex2d(actual2.getX(), actual.getY());
		GL11.glEnd();
		this.enableDefaults();
		GL11.glPopMatrix();
	}

	public  void renderBoundingBox(Entity entity, SpLocation loc) {
		AxisAlignedBB bb = entity.boundingBox;
		double xL = bb.maxX - bb.minX;
		double yL = (bb.maxY - bb.minY) * .65;
		double zL = bb.maxZ - bb.minZ;
		Float[] trans = getTranslation();
		SpLocation renderLoc = Util.getRenderLocationOfEntity(entity);
		double tx = loc.x;
		double ty = loc.y;
		double tz = loc.z;
		renderBoundingBox(tx,ty,tz,xL,yL,zL);
	}
	public  void renderBoundingBox(double d, double d1, double d2, double xLength, double yLength, double zLength) {
		GL11.glEnable(2848 /*GL_LINE_SMOOTH*/ );
		GL11.glPushMatrix(); // new "layer" of rendering.

		GL11.glTranslatef((float)d, (float)d1, (float)d2);
		GL11.glScalef(1,1,1); // although not technically neccessary, it's hard to say what the current scale is so set it to be sure.
		GL11.glDisable(GL11.GL_LIGHTING); //2896. Lighting does not apply to this "layer"
		GL11.glDepthMask(false); // nor does depth
		GL11.glDisable(GL11.GL_DEPTH_TEST); //2929. Don't test for depth
		GL11.glEnable(GL11.GL_BLEND); //3042 "blend" this layer with ones behind it (see-through)
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); // transparent color enabled basically
		GL11.glDisable(GL11.GL_TEXTURE_2D); //3553. Not drawing textures, just colors
		GL11.glLineWidth(1f); // 1f line width. Not sure how line width is determined but just fiddle w/ it
		//color.setOGLColor(); // Color of the line!
		GL11.glColor4f(1f, 0f, 0f,.2f);
		GL11.glDisable(GL11.GL_CULL_FACE); // dont worry about culling (selectively rendering polygons like quads)

		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); // render front and back, fill up whole area of quad
		drawBox(xLength,yLength,zLength); // draws a quad.
		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_LINE); // render front and back as just a set of lines
		drawBox(xLength,yLength,zLength); // draw again, but just the lines (different color).

		GL11.glPolygonMode(GL11.GL_FRONT_AND_BACK, GL11.GL_FILL); // set it back to normal
		GL11.glEnable(GL11.GL_CULL_FACE); // back to normal
		GL11.glEnable(3553 /*GL_TEXTURE_2D*/); //etc....
		GL11.glEnable(2929 /*GL_DEPTH_TEST*/);
		GL11.glDepthMask(true);
		GL11.glEnable(GL11.GL_LIGHTING);
		GL11.glDisable(3042 /*GL_BLEND*/);
		GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F);
		GL11.glPopMatrix(); // we are done w/ this layer
		GL11.glDisable(2848 /*GL_LINE_SMOOTH*/ );
		return;
	}

	public void drawRoundedRect(SpScreenCoord loc1, SpScreenCoord loc2, int radius, SpColor color) {
		setupOverlayRendering();
		disableDefaults();
		loc1 = loc1.asActualCoords();
		loc2 = loc2.asActualCoords();
		int newX = (int) Math.abs(loc1.getX()+radius);
		int newY = (int) Math.abs(loc1.getY()+radius);
		int newX1 = (int) Math.abs(loc2.getX()-radius);
		int newY1 = (int) Math.abs(loc2.getY()-radius);

		//Draw main (center) rectangle
		drawRect(newX, newY, newX1, newY1, color);


		/* Draw outside rectangles */
		//Left rectangle
		drawRect(loc1.getX(), newY, newX, newY1, color);
		//Right rectangles
		drawRect(newX1, newY, loc2.getX(), newY1, color);
		//Top rectangle
		drawRect(newX, loc1.getY(), newX1, newY, color);
		//Bottom rectangle
		drawRect(newX, newY1, newX1, loc2.getY(), color);

		//Draw curves
		drawQuarterCircle(newX,newY,radius,0,color);
		drawQuarterCircle(newX1,newY,radius,1,color);
		drawQuarterCircle(newX,newY1,radius,2,color);
		drawQuarterCircle(newX1,newY1,radius,3,color);
		enableDefaults();
	}

	public void disableLightmap() {
		Minecraft.getMinecraft().entityRenderer.disableLightmap(0);
	}
	
	public void enableLightmap() {
		Minecraft.getMinecraft().entityRenderer.enableLightmap(0);
	}
	
	private void drawQuarterCircle(int x, int y, int radius, int mode, SpColor color)
	{
		setupOverlayRendering();
		disableDefaults();
		color.setOGLColor();
		GL11.glBegin(GL11.GL_POLYGON);
		GL11.glVertex2d(x, y);
		if(mode==0) {
			for (int i = 0; i <= 90; i++) {
				GL11.glVertex2d(x + (Math.sin((i * 3.141526D / 180)) * (radius*-1)), y + (Math.cos((i * 3.141526D / 180)) * (radius*-1)));
			}
		} else if(mode==1) {
			for (int i = 90; i <= 180; i++) {
				GL11.glVertex2d(x + (Math.sin((i * 3.141526D / 180)) * radius), y + (Math.cos((i * 3.141526D / 180)) * radius));
			}
		} else if(mode==2) {
			for (int i = 90; i <= 180; i++) {
				GL11.glVertex2d(x + (Math.sin((i * 3.141526D / 180)) * (radius*-1)), y + (Math.cos((i * 3.141526D / 180)) * (radius*-1)));
			}
		} else if(mode==3) {
			for (int i = 0; i <= 90; i++) {
				GL11.glVertex2d(x + (Math.sin((i * 3.141526D / 180)) * radius), y + (Math.cos((i * 3.141526D / 180)) * radius));
			}
		} else {
		}
		GL11.glEnd();
		enableDefaults();
	}

	private  void drawRect(double x, double y, double x1, double y1, SpColor color)
	{
		setupOverlayRendering();
		disableDefaults();
		color.setOGLColor();
		GL11.glBegin(GL11.GL_QUADS);
		GL11.glVertex2d(x1, y);
		GL11.glVertex2d(x, y);
		GL11.glVertex2d(x, y1);
		GL11.glVertex2d(x1, y1);
		GL11.glEnd();
		enableDefaults();
	}

	private  void drawBox(double xLength, double yLength, double zLength) {
		//GL11.glBegin(GL11.GL_QUADS);
		
		SpVBO vbo = new SpVBO(GL11.GL_QUADS, true, false, false, false, 24);
		vbo.createBuffer();
		
		vbo.addVertex(-xLength, -yLength, zLength);
		vbo.addVertex(xLength, -yLength, zLength); //top
		vbo.addVertex(xLength, -yLength, -zLength);
		vbo.addVertex(-xLength, -yLength, -zLength);

		vbo.addVertex(-xLength, yLength, zLength); // bottom
		vbo.addVertex(xLength, yLength, zLength);
		vbo.addVertex(xLength, yLength, -zLength);
		vbo.addVertex(-xLength, yLength, -zLength);

		vbo.addVertex(-xLength, yLength, -zLength); 
		vbo.addVertex(xLength, yLength, -zLength); // front
		vbo.addVertex(xLength, -yLength, -zLength);
		vbo.addVertex(-xLength, -yLength, -zLength);


		vbo.addVertex(-xLength, yLength, zLength);
		vbo.addVertex(xLength, yLength, zLength); //back
		vbo.addVertex(xLength, -yLength, zLength);
		vbo.addVertex(-xLength, -yLength, zLength);


		vbo.addVertex(-xLength, -yLength, zLength);
		vbo.addVertex(-xLength, yLength, zLength); // left
		vbo.addVertex(-xLength, yLength, -zLength);
		vbo.addVertex(-xLength, -yLength, -zLength);

		vbo.addVertex(xLength, -yLength, zLength);
		vbo.addVertex(xLength, yLength, zLength);
		vbo.addVertex(xLength, yLength, -zLength); //right
		vbo.addVertex(xLength, -yLength, -zLength);
		vbo.createVBO();
		vbo.draw();
		//GL11.glEnd();
	}

	public void setupOverlayRendering()
	{

		GL11.glClear(256);
		GL11.glMatrixMode(GL11.GL_PROJECTION);
		GL11.glLoadIdentity();
		// GL11.glOrtho(0.0D, var1.getScaledWidth_double(), var1.getScaledHeight_double(), 0.0D, 1000.0D, 3000.0D);
		GL11.glOrtho(0.0d, Sparrow.mc().screenWidth(), Sparrow.mc().screenHeight(), 0, 1000d, 3000d);
		//nn System.out.println("arguing width is: " + Sparrow.mc.displayWidth);
		//GL11.glOrtho(0.0D, getScreenWidth() * .5, getScreenHeight() * .5, 0.0D, 1000D, 3000D);
		GL11.glMatrixMode(5888 /*GL_MODELVIEW0_ARB*/);
		GL11.glLoadIdentity();
		GL11.glTranslatef(0.0F, 0.0F, -2000F);

	}

	public  void disableDefaults()
	{
		GL11.glEnable(GL11.GL_BLEND);
		GL11.glDisable(GL11.GL_LIGHTING);
		GL11.glDisable(GL11.GL_TEXTURE_2D);
	}
	public  void enableDefaults()
	{
		GL11.glDisable(GL11.GL_BLEND);
		GL11.glEnable(GL11.GL_TEXTURE_2D);
		GL11.glEnable(GL11.GL_LIGHTING); //fixes the weird sky-turning dark error
	}

	public void resetTranslation() {
		FloatBuffer fb = BufferUtils.createFloatBuffer(16);
		GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, fb);
		fb.rewind();
		Float x = fb.get(12); 
		Float y = fb.get(13); 
		Float z = fb.get(14);
		GL11.glTranslatef(-x, -y, -z);
	}

	private Float[] getTranslation() {
		Float[] trans = new Float[3];
		FloatBuffer fb = BufferUtils.createFloatBuffer(16);
		GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, fb);
		fb.rewind();
		trans[0] = fb.get(12);
		trans[1] = fb.get(13);
		trans[2] = fb.get(14);
		return trans;
	}
}
